package com.free.semantic.core.service.impl;

import com.free.semantic.common.Ls;
import com.free.semantic.core.ConceptInstanceManage;
import com.free.semantic.core.ConceptManage;
import com.free.semantic.core.conceptservice.ConceptService;
import com.free.semantic.core.impl.ConceptInstanceManageImpl;
import com.free.semantic.core.impl.ConceptManageImpl;
import com.free.semantic.core.proxy.ProxyFunctionProvider;
import com.free.semantic.core.proxy.impl.ConceptInsManageProxy;
import com.free.semantic.core.script.SemanticNetEngine;
import com.free.semantic.core.script.impl.ScriptEngineImpl;
import com.free.semantic.core.service.ConceptGroupManage;
import com.free.semantic.core.subconcept.SubConceptInstanceProvider;
import com.free.semantic.core.subconcept.impl.Temperature;
import com.free.semantic.core.subconcept.impl.WeatherProviderImpl;
import com.free.semantic.core.takeclient.ConceptInsTakeCommand;
import com.free.semantic.core.takeclient.impl.LocalManageImpl;
import com.free.semantic.core.takeclient.impl.UrlClientImpl;
import com.free.semantic.req.RelationDefineGroup;
import com.free.semantic.utils.Utils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;

import static com.free.semantic.core.concept.impl.ConceptSelfInfoConcept.FIND_MORE;
import static com.free.semantic.core.concept.impl.ConceptSelfInfoConcept.FIND_ONE;
import static com.free.semantic.utils.Utils.*;

@Component
public class ConceptGroupManageImpl implements ConceptGroupManage {

    @Value("${baseUrl}")
    private String baseUrl;

    private static final String THREE_FIND_ONE = "threeFindOne";

    private static final String TWO_FIND_ONE = "twoFindOne";

    private static final String MORE_FIND_ONE = "moreFindOne";

    Map<String, ConceptInstanceManage> manageMap = new LinkedHashMap<>();

    Map<String, String> conceptMangeURL = new HashMap<>();

    Map<String, Long> manageMapId = new LinkedHashMap<>();

    SemanticNetEngine scriptEngine = new ScriptEngineImpl();

    ConceptInstanceManage instanceManage;

    @Resource
    private ConceptService conceptService;

    @PostConstruct
    public void build() {

        buildBaseManage();

        {

            String modelName = "省份城市模型";
            RelationDefineGroup group1 = new RelationDefineGroup();
            // relation 包含(A,B)
            defineRelation(group1, "包含", defineItem(oneObj("A"), moreObj("B")), // A->B=[0,) //代表 针对任意一个A，都可以找到 [0,)个B与之对应
                    defineItem(oneObj("B"), oneObj("A"))); // B->A=1 //代表 针对任意一个B，都可以找到 1个A与之对应

            // 使用包含关系 定义一个语义网络
            ConceptManage model1 = getConceptManage(group1);
            // object 省份 城市
            object(model1, "省份", "城市");
            // 包含(省份,城市)
            createRelation(model1, "包含", "省份", "城市");

            // 创建模型的一个实现，并且实现 省份查询城市 和 城市查询 省份 函数（添加一些测试数据）
            ConceptInstanceManage modelInstance = new ConceptInstanceManageImpl(model1, buildMap("省份", "城市",
                    new String[][]{{"浙江", "杭州"}, {"浙江", "金华"}, {"山西", "长治"}, {"山西", "运城"}, {"广东", "广州"}, {"广东", "珠海"}}));
            manageMap.put(modelName, modelInstance);
            String url = baseUrl + String.format("/manage/controller/%s/semantic", modelName);
            conceptMangeURL.put(modelName, url);
        }

        {

            String modelName = "provinceCityModel";
            RelationDefineGroup group1 = new RelationDefineGroup();
            // relation 包含(A,B)
            defineRelation(group1, "包含", defineItem(oneObj("A"), moreObj("B")), // A->B=[0,) //代表 针对任意一个A，都可以找到 [0,)个B与之对应
                    defineItem(oneObj("B"), oneObj("A"))); // B->A=1 //代表 针对任意一个B，都可以找到 1个A与之对应

            // 使用包含关系 定义一个语义网络
            ConceptManage model1 = getConceptManage(group1);
            // object 省份 城市
            object(model1, "province", "city");
            // 包含(省份,城市)
            createRelation(model1, "包含", "province", "city");

            // 创建模型的一个实现，并且实现 省份查询城市 和 城市查询 省份 函数（添加一些测试数据）
            ConceptInstanceManage modelInstance = new ConceptInstanceManageImpl(model1, buildMap("province", "city",
                    new String[][]{{"浙江", "杭州"}, {"浙江", "金华"}, {"山西", "长治"}, {"山西", "运城"}, {"广东", "广州"}, {"广东", "珠海"}}));
            manageMap.put(modelName, modelInstance);
            String url = baseUrl + String.format("/manage/controller/%s/semantic", modelName);
            conceptMangeURL.put(modelName, url);
        }
        {
            String modelName = "身高体重";

            RelationDefineGroup group1 = new RelationDefineGroup();
            defineRelation(group1, "属性", defineItem(oneObj("A"), oneObj("B")));

            ConceptManage personInfoModel = getConceptManage(group1);
            //object 人 身高 体重
            personInfoModel.addConcept("人", "身高", "体重", "数字");

            //属性(人,身高)
            createRelation(personInfoModel, "属性", "人", "身高");
            //属性(人,体重)
            createRelation(personInfoModel, "属性", "人", "体重");
            //单属性(身高,数字)
            createRelation(personInfoModel, "属性", "身高", "数字");
            //单属性(体重,数字)
            createRelation(personInfoModel, "属性", "体重", "数字");
            //ConceptInstanceManage modelInstance = null;
            /**
             * 创建模型的一个实现，并且实现 国家，省份 和城市之间的互相查询
             */
            ConceptInstanceManage modelInstance = new ConceptInstanceManageImpl(personInfoModel,
                    buildMap("人", "体重", new String[][]{{"张三", "65kg"}}),
                    buildMap("人", "身高", new String[][]{{"张三", "180cm"}}),
                    Utils.buildMap("体重", "数字", new String[][]{{"65kg", "65"}}),
                    Utils.buildMap("身高", "数字", new String[][]{{"180cm", "180"}})
            );
            manageMap.put(modelName, modelInstance);
            String url = baseUrl + String.format("/manage/controller/%s/semantic", modelName);
            conceptMangeURL.put(modelName, url);
        }
        addModel(new Temperature());
        addModel(new WeatherProviderImpl());

        {
            String modelName = "医院模型";
            RelationDefineGroup group1 = new RelationDefineGroup();

            // 定义关系类型
            defineRelation(group1, "包含", defineItem(oneObj("A"), moreObj("B")),
                    defineItem(oneObj("B"), oneObj("A")));
            defineRelation(group1, "工作于", defineItem(oneObj("A"), oneObj("B")),
                    defineItem(oneObj("B"), moreObj("A")));
            defineRelation(group1, "患有", defineItem(oneObj("A"), moreObj("B")),
                    defineItem(oneObj("B"), moreObj("A")));
            defineRelation(group1, "治疗", defineItem(oneObj("A"), moreObj("B")),
                    defineItem(oneObj("B"), moreObj("A")));
            defineRelation(group1, "开具", defineItem(oneObj("A"), moreObj("B")),
                    defineItem(oneObj("B"), oneObj("A")));
            defineRelation(group1, "参与", defineItem(oneObj("A"), moreObj("B")),
                    defineItem(oneObj("B"), moreObj("A")));
            defineRelation(group1, "记录", defineItem(oneObj("A"), oneObj("B")));
            defineRelation(group1, "发生于", defineItem(oneObj("A"), oneObj("B")));

            // 定义模型
            ConceptManage hospitalModel = getConceptManage(group1);

            // 添加概念
            object(hospitalModel, "医院", "科室", "医生", "患者", "疾病", "药品", "问诊", "问诊时间", "问诊结果");

            // 创建关系
            createRelation(hospitalModel, "包含", "医院", "科室");
            createRelation(hospitalModel, "工作于", "医生", "科室");
            createRelation(hospitalModel, "患有", "患者", "疾病");
            createRelation(hospitalModel, "治疗", "医生", "疾病");
            createRelation(hospitalModel, "开具", "医生", "药品");
            createRelation(hospitalModel, "参与", "医生", "问诊");
            createRelation(hospitalModel, "参与", "患者", "问诊");
            createRelation(hospitalModel, "记录", "问诊", "问诊结果");
            createRelation(hospitalModel, "发生于", "问诊", "问诊时间");

            // 创建实例，添加样本数据
            ConceptInstanceManage modelInstance = new ConceptInstanceManageImpl(hospitalModel,
                    buildMap("医院", "科室", new String[][]{
                            {"浙江省人民医院", "内科"}, {"浙江省人民医院", "外科"}, {"浙江省人民医院", "儿科"},
                            {"杭州市第一医院", "内科"}, {"杭州市第一医院", "妇产科"}, {"杭州市第一医院", "神经科"}
                    }),
                    buildMap("医生", "科室", new String[][]{
                            {"张医生", "内科"}, {"李医生", "外科"}, {"王医生", "儿科"},
                            {"赵医生", "妇产科"}, {"钱医生", "神经科"}, {"孙医生", "内科"}
                    }),
                    buildMap("患者", "疾病", new String[][]{
                            {"患者A", "感冒"}, {"患者A", "高血压"}, {"患者B", "骨折"},
                            {"患者C", "糖尿病"}, {"患者D", "肺炎"}
                    }),
                    buildMap("医生", "疾病", new String[][]{
                            {"张医生", "感冒"}, {"张医生", "高血压"}, {"李医生", "骨折"},
                            {"王医生", "感冒"}, {"赵医生", "妇科疾病"}, {"钱医生", "脑梗"}
                    }),
                    buildMap("医生", "药品", new String[][]{
                            {"张医生", "感冒药"}, {"张医生", "降压药"}, {"李医生", "消炎药"},
                            {"王医生", "儿童感冒药"}, {"钱医生", "脑循环改善药"}
                    }),
                    buildMap("医生", "问诊", new String[][]{
                            {"张医生", "问诊1"}, {"张医生", "问诊2"}, {"李医生", "问诊3"},
                            {"王医生", "问诊4"}, {"赵医生", "问诊5"}
                    }),
                    buildMap("患者", "问诊", new String[][]{
                            {"患者A", "问诊1"}, {"患者A", "问诊2"}, {"患者B", "问诊3"},
                            {"患者C", "问诊4"}, {"患者D", "问诊5"}
                    }),
                    buildMap("问诊", "问诊结果", new String[][]{
                            {"问诊1", "轻度感冒，建议多喝水"}, {"问诊2", "高血压，需要长期服药"},
                            {"问诊3", "腿部骨折，需要手术"}, {"问诊4", "需调整胰岛素剂量"},
                            {"问诊5", "妇科炎症，需抗生素治疗"}
                    }),
                    buildMap("问诊", "问诊时间", new String[][]{
                            {"问诊1", "2023-06-15"}, {"问诊2", "2023-06-20"},
                            {"问诊3", "2023-07-01"}, {"问诊4", "2023-07-15"},
                            {"问诊5", "2023-08-01"}
                    })
            );

            manageMap.put(modelName, modelInstance);
            String url = baseUrl + String.format("/manage/controller/%s/semantic", modelName);
            conceptMangeURL.put(modelName, url);
        }
    }

    public void buildBaseManage() {
        RelationDefineGroup group = new RelationDefineGroup();

        defineRelation(group, TWO_FIND_ONE, defineItem(oneObj("A", "B"), moreObj("C")));

        defineRelation(group, THREE_FIND_ONE, defineItem(oneObj("A", "B", "C"), moreObj("D")));

        defineRelation(group, MORE_FIND_ONE, defineItem(moreObj("A"), oneObj("B")));

        ConceptManage model = getConceptManage(group);

        object(model, "@语义网络组", "语义网络组", "语义网络", "语义网络实现URL", "语义网络名称",
                "创建", "复制", "删除", "导入", "注册实现器", "语义网络脚本", "执行", "实现器", "实现器名称", "保存");

        createRelation(model, FIND_MORE, "语义网络组", "语义网络名称");
        createRelation2(model, TWO_FIND_ONE, "@语义网络组", "语义网络名称", "创建");
        createRelation2(model, FIND_ONE, "语义网络名称", "语义网络");
        createRelation2(model, FIND_ONE, "语义网络", "复制");
        createRelation2(model, FIND_ONE, "语义网络", "删除");
        createRelation2(model, FIND_ONE, "语义网络", "保存");
        createRelation2(model, FIND_ONE, "语义网络名称", "语义网络实现URL");

        createRelation2(model, THREE_FIND_ONE, "@语义网络组", "语义网络名称", "语义网络实现URL", "导入");
        createRelation2(model, THREE_FIND_ONE, "语义网络", "实现器", "实现器名称", "注册实现器");
        createRelation2(model, TWO_FIND_ONE, "语义网络名称", "语义网络脚本", "执行");

        instanceManage = new ConceptInstanceManageImpl(model);

        instanceManage.registerFunction(Ls.of("语义网络组"), "语义网络名称",
                context -> {
                    List<String> conceptNameList = new ArrayList<>(manageMap.keySet());
                    context.setValue("语义网络名称", conceptNameList);
                });

        instanceManage.registerFunction(Ls.of("@语义网络组", "语义网络名称"), "创建",
                context -> {
                    String name = (String) context.getListValue("语义网络名称").get(0);
                    if (manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("已经存在名为%s的语义网络", name));
                    }
                    conceptMangeURL.put(name, baseUrl + String.format("/manage/controller/%s/semantic/", name));
                    ConceptManage conceptManage = new ConceptManageImpl();
                    ConceptInstanceManage ins = new ConceptInstanceManageImpl(conceptManage);
                    manageMap.put(name, ins);
                    context.setValue("创建", "success");
                });

        instanceManage.registerFunction(Ls.of("语义网络名称"), "语义网络",
                context -> {
                    String name = (String) context.getListValue("语义网络名称").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    context.setValue("语义网络", name);
                });

        instanceManage.registerFunction(Ls.of("语义网络"), "复制",
                context -> {
                    String name = (String) context.getListValue("语义网络").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    ConceptInstanceManage conceptInstanceManage = manageMap.get(name);
                    ConceptInsTakeCommand client = new LocalManageImpl(conceptInstanceManage);

                    SemanticNetEngine engine = new ScriptEngineImpl();
                    ConceptManage conceptManage = engine.buildManageFromTake(client);


                    ProxyFunctionProvider provider = new ProxyFunctionProvider(conceptManage, conceptInstanceManage);
                    provider.prepareFunctionMap();

                    ConceptInstanceManage ins = new ConceptInstanceManageImpl(conceptManage, provider);

                    manageMap.put(name + "副本", ins);
                    conceptMangeURL.put(name + "副本", baseUrl + String.format("/manage/controller/%s/semantic/", name + "副本"));
                    context.setValue("复制", "success");
                });

        instanceManage.registerFunction(Ls.of("语义网络"), "删除",
                context -> {
                    String name = (String) context.getListValue("语义网络").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    manageMap.remove(name);
                    conceptMangeURL.remove(name);
                    context.setValue("删除", "success");
                });

        instanceManage.registerFunction(Ls.of("语义网络"), "保存",
                context -> {
                    String name = (String) context.getListValue("语义网络").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }

                    ConceptInstanceManage conceptInstanceManage = manageMap.get(name);




                    conceptMangeURL.remove(name);
                    context.setValue("删除", "success");
                });


        instanceManage.registerFunction(Ls.of("语义网络名称"), "语义网络实现URL",
                context -> {
                    String name = (String) context.getListValue("语义网络名称").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    String url = conceptMangeURL.get(name);
                    context.setValue("语义网络实现URL", url);
                });

        instanceManage.registerFunction(Ls.of("@语义网络组", "语义网络名称", "语义网络实现URL"), "导入",
                context -> {
                    String name = (String) context.getListValue("语义网络名称").get(0);
                    if (manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("已经存在名为%s的语义网络", name));
                    }
                    String url = (String) context.getListValue("语义网络实现URL").get(0);
                    UrlClientImpl urlClient = new UrlClientImpl(url);
                    ConceptInsManageProxy proxy = new ConceptInsManageProxy(urlClient);
                    manageMap.put(name, proxy);
                    conceptMangeURL.put(name, baseUrl + String.format("/manage/controller/%s/semantic/", name));
                    context.setValue("导入", "success");
                });

        instanceManage.registerFunction(Ls.of("语义网络", "实现器", "实现器名称"), "注册实现器",
                context -> {
                    String name = (String) context.getListValue("语义网络").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    String url = (String) context.getListValue("实现器").get(0);
                    String providerName = (String) context.getListValue("实现器名称").get(0);
                    UrlClientImpl client = new UrlClientImpl(url);

                    ConceptInsManageProxy proxy = new ConceptInsManageProxy(client);
                    manageMap.get(name).registerFunction(providerName, relationItem ->
                            proxy.getFunction(relationItem.getSourceObjectList(), relationItem.getDestObject()));
                    context.setValue("注册实现器", "success");
                });

        instanceManage.registerFunction(Ls.of("语义网络名称", "语义网络脚本"), "执行",
                context -> {
                    String name = (String) context.getListValue("语义网络名称").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    String script = (String) context.getListValue("语义网络脚本").get(0);
                    ConceptInstanceManage manage = manageMap.get(name);
                    Object object = scriptEngine.execScript(manage, script);
                    context.setValue("执行", object);
                });
    }


    private void addModel(SubConceptInstanceProvider manage) {
        String modelName = manage.getName();
        manageMap.put(modelName, manage.getInstanceMange());
        String url = baseUrl + String.format("/manage/controller/%s/semantic", modelName);
        conceptMangeURL.put(modelName, url);
    }

    @Override
    public ConceptInstanceManage getManage(String conceptName) {
        if (StringUtils.isBlank(conceptName)) {
            return instanceManage;
        } else {
            return manageMap.get(conceptName);
        }
    }

    @Override
    public void add(String conceptName, ConceptInstanceManage manage) {

    }

}
